#include "context.h"

void Context::GetParameters(params param)
{
    switch (param) {
            // 基础算子参数 logN = 15，Q = 39bit + 17 * 36bit，P = 6 * 41bit
        case params::logN15QP881:
            qVec = { 
                36028797017456641, 36028797014704129, 36028797014573057, 36028797014376449, 36028797013327873, 
                36028797013000193, 36028797012606977, 36028797010444289, 36028797009985537, 36028797005856769, 
                36028797005529089, 36028797005135873, 36028797003694081, 36028797003563009, 36028797001138177,
            };
            pVec = { 72057594037338113 };
            tVec = { 786433 };
            break;
            // 自举测试参数 logN = 12, Q = 28 * 54bit, P = 4 * 60bit
        case params::logN12QP884:
            qVec = { 
                0x7ffffffffe70001, 0x7ffffffffe10001, 0x7ffffffffcc0001, // 59 + 59 + 59 bits
                0x400000000270001, 0x400000000350001, 0x400000000360001, // 58 + 58 + 58 bits
                0x3ffffffffc10001, 0x3ffffffffbe0001, 0x3ffffffffbd0001, // 58 + 58 + 58 bits
                0x4000000004d0001, 0x400000000570001, 0x400000000660001  //702
            };
            pVec = {0xffffffffffc0001, 0x10000000001d0001, 0x10000000006e0001};
            tVec = {65537};
            break;
    }
}

void Context::GetParametersLambda(long logN, int lambda, int dNum)
{
    switch (lambda) {
        case 128: {
            switch(logN) {
                case 16: {
                    if((dNum <= 0) || (dNum > L)) {
                        L = 28;
                        K = 4;
                        qVec = {36028797001138177, 36028796997599233, 36028796996681729, 36028796992749569, 
                                36028796991700993, 36028796990390273, 36028796987637761, 36028796986851329, 
                                36028796984098817, 36028796982263809, 36028796982132737, 36028796980953089, 
                                36028796974661633, 36028796973088769, 36028796972040193, 36028796971253761, 
                                36028796970074113, 36028796967976961, 36028796967190529, 36028796966141953, 
                                36028796965224449, 36028796964569089, 36028796960243713, 36028796952379393, 
                                36028796950675457, 36028796950020097, 36028796949626881, 36028796945170433, };
                        pVec = {36028797014376449, 36028797013327873, 36028797010444289, 36028797005856769, };
                        tVec = { 786433 };
                        
                        break;
                    }
                    else {
                        L = 32 / (dNum + 1) * dNum;
                        K = 32 / (dNum + 1);
                        tVec = { 786433 };
                        GetPrimes(lambda, logN, logp);
                        break;
                    }
                }
                case 15: {
                    if((dNum <= 0) || (dNum > L)) {
                        qVec = { 
                            36028797017456641, 36028797014704129, 36028797014573057, 36028797014376449, 36028797013327873, 
                            36028797013000193, 36028797012606977, 36028797010444289, 36028797009985537, 36028797005856769, 
                            36028797005529089, 36028797005135873, 36028797003694081, 36028797003563009, 36028797001138177,
                        };
                        pVec = { 72057594037338113 };
                        tVec = { 65537 };
                        break;
                    }
                    else {
                        L = 16 / (dNum + 1) * dNum;
                        K = 16 / (dNum + 1);
                        tVec = { 65537 };
                        GetPrimes(lambda, logN, logp);
                        break;
                    }
                }
                case 14: {
                    if((dNum <= 0) || (dNum > L)) {
                        L = 7;
                        K = 1;
                        qVec = {36028797016178689, 36028797014704129, 36028797014573057, 36028797014376449, 
                                36028797014081537, 36028797013327873, 36028797013098497, };
                        pVec = {36028797017456641, };
                        tVec = { 65537 };
                        GetPrimes(lambda, logN, 55);
                        break;
                    }
                    else {
                        L = 8 / (dNum + 1) * dNum;
                        K = 8 / (dNum + 1);
                        tVec = { 65537 };
                        GetPrimes(lambda, logN, logp);
                        break;
                    }
                }
                case 13: {
                    L = 3;
                    K = 1;
                    qVec = {0x3fffffffef8001, 0x4000000011c001, 0x40000000120001};
                    pVec = {0x7ffffffffb4001};
                    tVec = { 65537 };
                    break;
                }
                default: 
                    throw std::domain_error("Invalid value for logN.");
            }    
            break;
        }
        case 192: {
            switch(logN) {
                case 16: {
                    if((dNum <= 0) || (dNum > L)) {
                        L = 18;
                        K = 4;
                        qVec = {36028797001138177, 36028796997599233, 36028796996681729, 36028796992749569, 
                                36028796991700993, 36028796990390273, 36028796987637761, 36028796986851329, 
                                36028796984098817, 36028796982263809, 36028796982132737, 36028796980953089, 
                                36028796974661633, 36028796973088769, 36028796972040193, 36028796971253761, 
                                36028796970074113, 36028796967976961, };
                        pVec = {36028797014376449, 36028797013327873, 36028797010444289, 36028797005856769, };
                        tVec = { 786433 };
                        break;
                    }
                    else {
                        logp = 51;
                        L = 24 / (dNum + 1) * dNum;
                        K = 24 / (dNum + 1);
                        tVec = { 786433 };
                        GetPrimes(lambda, logN, logp);
                        break;
                    }
                }
                case 15: {
                    if((dNum <= 0) || (dNum > L)) {
                        logp = 50;
                        L = 8;
                        K = 4;
                        qVec = {1125899902124033, 1125899901665281, 1125899899174913, 1125899896160257, 
                                1125899887312897, 1125899886395393, 1125899885740033, 1125899885412353, };
                        pVec = {1125899904679937, 1125899903827969, 1125899903500289, 1125899903107073, };
                        tVec = { 786433 };
                        break;
                    }
                    else {
                        L = 12 / (dNum + 1) * dNum;
                        K = 12 / (dNum + 1);
                        tVec = { 786433 };
                        GetPrimes(lambda, logN, logp);
                        break;
                    }
                }
                case 14: {
                    if((dNum <= 0) || (dNum > L)) {
                        logp = 50;
                        L = 4;
                        K = 2;
                        qVec = {1125899903827969, 1125899903795201, 1125899903500289, 1125899903107073, };
                        pVec = {1125899904679937, 1125899903991809, };
                        tVec = { 786433 };
                        break;
                    }
                    else {
                        L = 6 - 6 / (dNum + 1);
                        K = 6 / (dNum + 1);
                        tVec = { 65537 };
                        GetPrimes(lambda, logN, logp);
                        break;
                    }
                }
                case 13: {
                    logp = 40;
                    L = 3;
                    K = 1;
                    qVec = {1099510890497, 1099510824961, 1099510054913, };
                    pVec = {1099511480321, };
                    tVec = { 786433 };
                    break;
                }
                default: 
                    throw std::domain_error("Invalid value for logN.");
            }
        }
    }
}

bool isPrime(uint64_t n) {
    if (n <= 1) {
        return false;
    }
    if (n == 2) {
        return true;
    }
    if (n % 2 == 0) {
        return false;
    }
    for (uint64_t i = 3; i <= std::sqrt(n); i += 2) {
        if (n % i == 0) return false;
    }
    
    return true;
}

void Context::GetPrimes(uint64_t lambda, uint64_t logN, uint64_t bit)
{
    N = 1L << logN;
    uint64_t a = (1L << bit) + 1;
    for(int i = 0; i < K; i++) {
        while (true) {
            a -= (2 * N);
            if (isPrime(a)) {
                pVec.push_back(a);
                break;
            }
        } 
    }
    for(int i = 0; i < L; i++) {
        while (true) {
            a -= (2 * N);
            if (isPrime(a)) {
                qVec.push_back(a);
                break;
            }
        }  
    }
}